package com.harveyspace.aes.social.utils;

import com.harveyspace.aes.core.common.Constants;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

/**
 * SSL Http Client
 *
 * @Author <a href="harveyer@163.com">harvey</a>
 * @date 2018/2/9
 */
public class HttpClientSSL {

    private static final int TIMEOUT = 15000;

    public static String getString(String url, Map<String, String> headers, int socketTimeout) throws Exception {

        // 采用绕过验证的方式处理https请求
        SSLContext sslContext = createIgnoreVerifySSL();

        // 设置协议http和https对应的处理socket链接工厂的对象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();

        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

        // 创建自定义的httpClient对象
        CloseableHttpClient client = HttpClients.custom()
                .setConnectionManager(connManager)
                .build();

        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(socketTimeout)
                .setConnectTimeout(socketTimeout)
                .build();

        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);

        if (null != headers) {
            headers.forEach(httpGet::setHeader);
        }

        try {

            //执行请求操作，并拿到结果（同步阻塞）
            CloseableHttpResponse response = client.execute(httpGet);
            HttpEntity httpEntity = response.getEntity();

            String body = "";

            if (httpEntity != null) {
                body = EntityUtils.toString(httpEntity, Constants.DEFAULT_CHARSET);
            }

            EntityUtils.consume(httpEntity);

            response.close();

            return body;

        } finally {
            client.close();
        }
    }

    public static String getString(String url, Map<String, String> headers) throws Exception {

        return getString(url, headers, TIMEOUT);
    }

    public static String getString(String url) throws Exception {

        return getString(url, null, TIMEOUT);
    }

    /**
     * postjson请求
     *
     * @param url           request url
     * @param jsonParams    request body
     * @param headers       request header
     * @param socketTimeout timeout
     * @return String
     * @throws Exception 异常
     */
    public static String postForJson(String url, String jsonParams, Map<String, String> headers, int socketTimeout) throws Exception {

        // 采用绕过验证的方式处理https请求
        SSLContext sslContext = createIgnoreVerifySSL();

        // 设置协议http和https对应的处理socket链接工厂的对象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();

        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

        // 创建自定义的httpClient对象
        CloseableHttpClient client = HttpClients.custom()
                .setConnectionManager(connManager)
                .build();

        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(socketTimeout)
                .setConnectTimeout(socketTimeout)
                .build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);

        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-type", "application/json;charset=UTF-8");

        if (null != headers) {
            headerMap.putAll(headers);
            headerMap.forEach(httpPost::setHeader);
        }

        StringEntity stringEntity = new StringEntity(jsonParams, Constants.DEFAULT_CHARSET);
        httpPost.setEntity(stringEntity);

        try {

            //执行请求操作，并拿到结果（同步阻塞）
            CloseableHttpResponse response = client.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();

            String body = "";

            if (httpEntity != null) {
                body = EntityUtils.toString(httpEntity, Constants.DEFAULT_CHARSET);
            }

            EntityUtils.consume(httpEntity);

            response.close();

            return body;

        } finally {
            client.close();
        }
    }

    public static String postForJson(String url, String jsonParams, Map<String, String> headers) throws Exception {

        return postForJson(url, jsonParams, headers, TIMEOUT);
    }

    public static String postForJson(String url, String jsonParams) throws Exception {

        return postForJson(url, jsonParams, null, TIMEOUT);
    }

    private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {

        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {

            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);

        return sc;
    }

}
